﻿using Inaction;
using Inaction.Core;
using Inaction.Mapping;
using System;
using System.ComponentModel;
using System.Linq;

namespace Inaction
{
    public abstract partial class Entity<T> : Core.IEntity
        where T : Entity<T>, new()
    {
        #region IEntity
        [Browsable(false)]
        public virtual bool AllowEdit
        {
            get { return true; }
        }
        [Browsable(false)]
        public virtual bool AllowRemove
        {
            get { return true; }
        }
        internal protected bool isNew = false;
        [Browsable(false)]
        public bool IsNew { get { return isNew; } }

        internal bool isDeleted = false;
        [Browsable(false)]
        public bool IsDeleted { get { return isDeleted; } }

        bool isSelfDirty = false;
        [Browsable(false)]
        public override bool IsSelfDirty
        {
            get { return isNew || isSelfDirty; }
        }

        Guid? primaryKey;
        [Browsable(false)]
        public Guid? PrimaryKey
        {
            get
            {
                if (primaryKey == null)
                {
                    primaryKey = (Guid?)ClassInfo.PrimaryKey.GetFieldValue((T)this);
                }
                return primaryKey;
            }
        }

        public override bool IsPropertyDirty(IProperty property)
        {
            if (!isSelfDirty) return false;
            var trackValue = PropertyTracks[property.Index];
            var currentValue = property.GetFieldValue(this);
            if (trackValue == null)
            {
                return currentValue != null;
            }
            else
            {
                return !trackValue.Equals(currentValue);
            }
        }

        public object GetOldValue(IProperty property)
        {
            return PropertyTracks[property.Index];
        }
        #endregion
        public virtual void MarkNew()
        {
            this.isNew = true;
        }
        public virtual void MarkDirty()
        {
            if (ClassInfo.UpdaterProperty != null)
            {
                ClassInfo.UpdaterProperty.SetFieldValue(this, Inaction.Security.Principal.Instance.Identity.UserNumber);
            }
            if (ClassInfo.UpdateTimeProperty != null)
            {
                ClassInfo.UpdateTimeProperty.SetFieldValue(this, DateTime.Now);
            }
        }
        public virtual void MarkDeleted()
        {
            isDeleted = true;
            if (ClassInfo.DeletedProperty != null)
            {
                ClassInfo.DeletedProperty.SetFieldValue(this, true);
            }
        }

        public static new T New()
        {
            var t = new T();
            t.SetDefaultValue();
            t.MarkNew();
            return t;
        }
        public static T New(T obj)
        {
            var t = new T();
            var classInfo = ClassInfo.LoadInfo(typeof(T));
            foreach (var p in classInfo.Properties)
            {
                p.SetFieldValue(t, p.GetFieldValue(obj));
            }
            foreach (var child in obj._childs)
            {
                t._childs.Add(child.Key, (IEntityList)child.Value.Clone());
            }
            t.MarkNew();
            return t;
        }

        [Browsable(false)]
        public virtual IEntity Master { get; set; }
    }
}